#pragma once 

#include <iostream>
#include <memory>
#include "epoller.hpp"
#include "Connection.hpp"
#include <unordered_map>
#include <utility>


using connection_t = std::shared_ptr<Connection>;
using namespace EpollerModule;

//这个只负责关心文件描述符的就绪状态
class Reactor 
{
public:    
Reactor()
        :_epoller(std::make_shared<epoller>()),
        _isrunning(false)
        {}
    void Init()
    {
        _epoller->Init();
    }
    bool IsConnectionExist(int fd)
    {
        return  _connections.find(fd) != nullptr; //存在返回true
    }
    void Dispacher(int n)
    {
        for (int i = 0; i < n; i++)
        {
            int fd = _revents[i].data.fd;
            uint32_t revents = _revents[i].events;
            //进行模块化处理
            if ((revents&EPOLLERR) || (revents&EPOLLHUP))
                revents = (EPOLLIN | EPOLLOUT); //把异常处理交给recv，避免了异常处理满天飞(简化代码)
            if ((revents&EPOLLIN) && IsConnectionExist(fd))
            {
                //注意这里我们是那fd作为key值的!!!
                _connections[fd]->CallRead();
            }
            if ((revents&EPOLLOUT) && IsConnectionExist(fd))
            {
                _connections[i]->CallWrite();
            }
        }
    }
    void LoopOnce()
    {
        int n = _epoller->Wait(_revents,64);
        Dispacher(n);
    }
    void Loop()
    {
        _isrunning = true;
        while(_isrunning)
        {
            LoopOnce();
        }
        _isrunning = false;
    }
    void InsertConnection(connection_t con)
    {
        if (_connections.find(con->Fd()) == _connections.end())
        {
            //1. 添加进入epollserver的关注队列当中
            _connections.insert(std::make_pair(con->Fd(),con));
            //2. 让epoll模型帮我关注
            _epoller->Insert(con->Fd(),con->Getevents());
        }
    }

    void Stop()
    {
        _isrunning = false;
    }
    ~Reactor(){}
private:
    std::shared_ptr<epoller> _epoller; 
    bool _isrunning;
    epoll_event _revents[64];
    std::unordered_map<int,connection_t> _connections; //管理每一个fd的 (处理读取不完善问题)
};